/**
* @File:mp3player.c
* @Version:V1.0
* @Author:rudius
* @Brief:
* @Logs:
* 	Date		Author		Notes
* 	2025-07-09	rudius		first version
*/

// <<< Use Configuration Wizard in Context Menu >>>

/* Private includes --------------------------------------------------------- */
#define MINIMP3_IMPLEMENTATION
#include "mp3player.h"
#include "stm32g0xx_hal.h"
#include "main.h"
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Private config ----------------------------------------------------------- */
/* Private defines ---------------------------------------------------------- */
// 最小缓冲区大小 (1152个样本 * 2通道)
#define MIN_BUF_SIZE (1152 * 2 * sizeof(short))
/* Private typedef ---------------------------------------------------------- */
/* Private variables -------------------------------------------------------- */
I2S_HandleTypeDef hi2s1;
/* Private function prototypes ---------------------------------------------- */
static void MX_I2S1_Init(void);
/*----------------------------------------------------------------------------*/
/* Private functions -------------------------------------------------------- */

/**
  * @brief I2S1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2S1_Init(void)
{

  /* USER CODE BEGIN I2S1_Init 0 */

  /* USER CODE END I2S1_Init 0 */

  /* USER CODE BEGIN I2S1_Init 1 */

  /* USER CODE END I2S1_Init 1 */
  hi2s1.Instance = SPI1;
  hi2s1.Init.Mode = I2S_MODE_MASTER_TX;
  hi2s1.Init.Standard = I2S_STANDARD_PHILIPS;
  hi2s1.Init.DataFormat = I2S_DATAFORMAT_16B;
  hi2s1.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
  hi2s1.Init.AudioFreq = I2S_AUDIOFREQ_8K;
  hi2s1.Init.CPOL = I2S_CPOL_LOW;
  if (HAL_I2S_Init(&hi2s1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2S1_Init 2 */

  /* USER CODE END I2S1_Init 2 */

}

static int mount_fatfs(struct mp3_player* player)
{
    FRESULT res = f_mount(&player->fatfs, "0:", 1); // 使用标准f_mount函数
    return (res == FR_OK) ? RT_EOK : -RT_ERROR;
}

static void decode_thread_entry(void* parameter)
{
    struct mp3_player* player = (struct mp3_player*)parameter;
    
    while (1) {
        rt_mutex_take(player->state_mutex, RT_WAITING_FOREVER);
        if (player->state != MP3_PLAYING) {
            rt_mutex_release(player->state_mutex);
            rt_thread_mdelay(10);
            continue;
        }
        rt_mutex_release(player->state_mutex);
        
        int free_buf = !player->active_buf;
        UINT bytes_read;
        
        FRESULT res = f_read(&player->file, 
                           player->input_buf, 
                           player->buf_size, 
                           &bytes_read);
        
        if (res != FR_OK || bytes_read <= 0) {
            rt_mutex_take(player->state_mutex, RT_WAITING_FOREVER);
            player->state = MP3_STOPPED;
            rt_mutex_release(player->state_mutex);
            continue;
        }
        
        int samples = mp3dec_decode_frame(
            &player->decoder,
            player->input_buf, 
            bytes_read,
            player->audio_buf[free_buf],
            &player->frame_info
        );
        
        if (player->frame_info.frame_bytes && samples) {
            player->sample_rate = player->frame_info.hz;
            rt_sem_release(player->buf_ready);
        }
    }
}

static void play_thread_entry(void* parameter)
{
    struct mp3_player* player = (struct mp3_player*)parameter;
    
    while (1) {
        rt_sem_take(player->buf_ready, RT_WAITING_FOREVER);
        rt_mutex_take(player->i2s_mutex, RT_WAITING_FOREVER);
        
        player->active_buf = !player->active_buf;
        int play_buf = !player->active_buf;
        int pcm_size = player->frame_info.frame_bytes;
        
        while (HAL_I2S_GetState(&hi2s1) != HAL_I2S_STATE_READY) {
            rt_thread_mdelay(1);
        }
        
        HAL_I2S_Transmit_DMA(
            &hi2s1, 
            (uint16_t*)player->audio_buf[play_buf], 
            pcm_size / 2
        );
        
        rt_mutex_release(player->i2s_mutex);
    }
}

/* Public functions --------------------------------------------------------- */
// 初始化MP3播放器对象
int mp3_player_init(struct mp3_player* player)
{
    RT_ASSERT(player != RT_NULL);
    MX_I2S1_Init();
    memset(player, 0, sizeof(*player));
    
    // 挂载文件系统（使用f_mount）
    if (mount_fatfs(player) != RT_EOK) {
        rt_kprintf("FATFS mount failed!\n");
        return -RT_ERROR;
    }
    
    player->state = MP3_STOPPED;
    player->volume = 80;
    player->state_mutex = rt_mutex_create("state_mtx", RT_IPC_FLAG_FIFO);
    player->buf_ready = rt_sem_create("buf_sem", 0, RT_IPC_FLAG_FIFO);
    player->i2s_mutex = rt_mutex_create("i2s_mtx", RT_IPC_FLAG_FIFO);
    
    player->decode_thread = rt_thread_create(
        "mp3_decode", decode_thread_entry, player, 2048, 12, 10);
    
    player->play_thread = rt_thread_create(
        "mp3_play", play_thread_entry, player, 2048, 10, 5);
    
    rt_thread_startup(player->decode_thread);
    rt_thread_startup(player->play_thread);
    return RT_EOK;
}

int mp3_player_open(struct mp3_player* player, const char* path)
{
    // 使用动态分配存储文件路径
    player->file_path = rt_strdup(path);
    
    FRESULT res = f_open(&player->file, path, FA_READ);
    if (res != FR_OK) {
        rt_kprintf("Open file failed: %d\n", res);
        return -RT_ERROR;
    }
    
    mp3dec_init(&player->decoder);
    player->buf_size = 16 * 1024;
    player->input_buf = rt_malloc(player->buf_size);
    player->audio_buf[0] = rt_malloc(MIN_BUF_SIZE * 2); // 加安全余量
    player->audio_buf[1] = rt_malloc(MIN_BUF_SIZE * 2);
    
    if (!player->input_buf || !player->audio_buf[0] || !player->audio_buf[1]) {
        rt_kprintf("Memory allocation failed\n");
        return -RT_ENOMEM;
    }
    return RT_EOK;
}

int mp3_player_play(struct mp3_player* player)
{
    rt_mutex_take(player->state_mutex, RT_WAITING_FOREVER);
    player->state = MP3_PLAYING;
    rt_mutex_release(player->state_mutex);
    return RT_EOK;
}

int mp3_player_pause(struct mp3_player* player)
{
// 暂停播放
    rt_mutex_take(player->state_mutex, RT_WAITING_FOREVER);
    player->state = MP3_PAUSED;
    rt_mutex_release(player->state_mutex);
    return RT_EOK;
}

// 停止播放
int mp3_player_stop(struct mp3_player* player)
{
    rt_mutex_take(player->state_mutex, RT_WAITING_FOREVER);
    if (player->state != MP3_PLAYING && player->state != MP3_PAUSED) {
        rt_mutex_release(player->state_mutex);
        return -RT_ERROR; // 只有在播放或暂停状态下才能停止
    }
    player->state = MP3_STOPPED;
    f_lseek(&player->file, 0);  // 重置文件指针
    rt_mutex_release(player->state_mutex);
    return RT_EOK;
}

// 设置音量
int mp3_player_set_volume(struct mp3_player* player, rt_uint8_t vol)
{
    rt_mutex_take(player->state_mutex, RT_WAITING_FOREVER);
    player->volume = (vol > 100) ? 100 : vol;
    rt_mutex_release(player->state_mutex);
    return RT_EOK;
}

// 释放播放器资源
void mp3_player_deinit(struct mp3_player* player)
{
    // 停止播放
    mp3_player_stop(player);
    
    // 关闭文件
    f_close(&player->file);

    // 取消文件系统挂载
    f_mount(0, "0:", 0);
    
    // 释放内存
    if (player->input_buf) rt_free(player->input_buf);
    if (player->audio_buf[0]) rt_free(player->audio_buf[0]);
    if (player->audio_buf[1]) rt_free(player->audio_buf[1]);
    rt_free(player->file_path); 

    // 删除同步对象
    rt_mutex_delete(player->state_mutex);
    rt_sem_delete(player->buf_ready);
    rt_mutex_delete(player->i2s_mutex);

    
    // 删除线程
    rt_thread_delete(player->decode_thread);
    rt_thread_delete(player->play_thread);
}

#ifdef __cplusplus
}
#endif
// <<< end of configuration section >>>
/* ----------------------------- end of mp3player.c ---------------------------- */